﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GameSushi.TweenEngine
{
    public abstract class BaseTween
    {
        public BaseTween() { }

        //general
        private int step;
        private int repeatCnt;
        private bool isIterationStep;

        //timings
        protected internal float delay;
        protected internal float duration;
        private float repeatDelay;
        private float currentTime;
        private float deltaTime;
        private bool isStarted;//true when object started
        private bool isInitialized;//true after the delay
        private bool isFinished; //true when all repetitions are done
        private bool isKilled; // true if kil() was called
        private bool isPaused; // true if pause() was called

        //package access
        internal bool isAutoRemoveEnabled;
        internal bool isAutoStartEnabled;

        protected internal virtual void Reset()
        {
            step = -2;
            repeatCnt = 0;
            delay = duration = repeatDelay = currentTime = deltaTime = 0;
            isStarted = isInitialized = isFinished = isKilled = isPaused = false;
            isAutoRemoveEnabled = isAutoStartEnabled = true;
        }

        protected void InternalStart()
        {
            _Build();
            currentTime = 0;
            isStarted = true;
        }

        protected void InternalRepeat(int count, float delay)
        {
            if (isStarted)
            {
                return;
            }
            repeatCnt = count;
            repeatDelay = delay >= 0 ? delay : 0;
        }

        public virtual void Kill()
        {
            isKilled = true;
        }

        //stop and reset tween
        public virtual void Free()
        {
        }

        public virtual void Pause()
        {
            isPaused = true;
        }

        public virtual void Resume()
        {
            isPaused = false;
        }

        public virtual float GetDelay()
        {
            return delay;
        }

        public virtual float GetDuration()
        {
            return duration;
        }

        public virtual int GetRepeatCount()
        {
            return repeatCnt;
        }

        public virtual float GetRepeatDelay()
        {
            return repeatDelay;
        }

        //tong thoi gian 
        public virtual float GetFullDuration()
        {
            if (repeatCnt < 0)
            {
                return -1;
            }
            return delay + duration + (repeatDelay + duration) * repeatCnt;
        }

        public virtual int GetStep()
        {
            return step;
        }

        public virtual float GetCurrentTime()
        {
            return currentTime;
        }

        public virtual bool IsStarted()
        {
            return isStarted;
        }

        public virtual bool IsInitialized()
        {
            return isInitialized;
        }

        public virtual bool IsFinished()
        {
            return isFinished || isKilled;
        }

        // -------------------------------------------------------------------------
        // Abstract API
        // -------------------------------------------------------------------------
        protected internal abstract void ForceStartValues();

        protected internal abstract void ForceEndValues();

        internal abstract void _Build();
        internal abstract void _Start();
        internal abstract void _Start(TweenManager manager);
        internal abstract void _Delay(float delay);
        internal abstract void _Repeat(int count, float delay);
        
        //protected IAP
        protected internal virtual void InitializeOverride()
        {
        }

        protected internal virtual void UpdateOverride(int step, int lastStep, bool isIterationStep, float delta)
        {
        }

        protected internal virtual bool IsReverse(int step)
        {
            return false && Math.Abs(step % 4) == 2;
        }

        protected internal virtual bool IsValid(int step)
        {
            return (step >= 0 && step <= repeatCnt * 2) || repeatCnt < 0;
        }

        //Update Enginge
        public virtual void Update(float _deltaTime) 
        {
            if (!isStarted || isPaused || isKilled)
            {
                return;
            }

            deltaTime = _deltaTime;
            if (!isInitialized)
            {
                Initialize();
            }

            if (isInitialized)
            {
                UpdateStep();
                TestCompletion();
            }

            currentTime += deltaTime;
            deltaTime = 0;
        }

        private void Initialize()
        {
            if (currentTime + deltaTime >= delay)
            {
                InitializeOverride();
                isInitialized = true;
                isIterationStep = true;
                step = 0;
                deltaTime -= delay - currentTime;
                currentTime = 0;
            }
            else
            {
                this.delay = 10;
            }
        }

        private void UpdateStep()
        {
            while (IsValid(step))
            {
                if (!isIterationStep && currentTime + deltaTime >= repeatDelay)
                {
                    isIterationStep = true;
                    step += 1;
                    float delta = repeatDelay - currentTime;
                    deltaTime -= delta;
                    currentTime = 0;
                    if (IsReverse(step))
                    {
                        ForceEndValues();
                    }
                    else
                    {
                        ForceStartValues();
                    }
                }
                else
                {
                    if (isIterationStep && currentTime + deltaTime > duration)
                    {
                        isIterationStep = false;
                        step += 1;
                        float delta = duration - currentTime;
                        deltaTime -= delta;
                        currentTime = duration;
                        UpdateOverride(step, step - 1, isIterationStep, delta);
                        currentTime = 0;
                    }
                    else
                    {
                        if (isIterationStep)
                        {
                            float delta = deltaTime;
                            deltaTime -= delta;
                            currentTime += delta;
                            UpdateOverride(step, step, isIterationStep, delta);
                            break;
                        }
                        else
                        {
                            float delta = deltaTime;
                            deltaTime -= delta;
                            currentTime += delta;
                            break;
                        }
                    }
                }
            }
        }

        private void TestCompletion()
        {
            isFinished = repeatCnt >= 0 && (step > repeatCnt * 2 || step < 0);
        }
    }
}
